#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "stack.h"

#define STACK_LIVE 0x1

// typedef struct stack_st
// {
//     void *arr;             // 存储数据数组
//     unsigned int elemsize; // 数据大小
//     unsigned int cap;      // 栈容量
//     unsigned int amout;    // 栈内含数据数量
//     unsigned char status;  // 状态
// } stack_t;

/// @brief 泛型交换函数
/// @param ptr1  变量地址
/// @param ptr2  变量地址
/// @param nbytes 变量数据大小
void swap(void *ptr1, void *ptr2, size_t nbytes)
{
    char tmp[nbytes];
    memcpy(tmp, ptr1, nbytes);
    memcpy(ptr1, ptr2, nbytes);
    memcpy(ptr2, tmp, nbytes);
}

stack_t *stack_create(unsigned int elemsize)
{
    int fail = 0;
    stack_t *stack = NULL;
    do
    {
        assert(elemsize > 0);
        stack = (stack_t *)malloc(sizeof(stack_t));
        assert(stack != NULL);
        int initcap = 2;

        stack->arr = malloc(elemsize * initcap);
        if (stack->arr == NULL)
        {
            fail = 1;
            break;
        }
        stack->elemsize = elemsize;
        stack->cap = initcap;
        stack->amout = 0;
        stack->status |= STACK_LIVE; // 设置存活状态
    } while (0);

    if (fail == 1)
        if (stack)
        {
            free(stack);
            stack = NULL;
        }

    return stack;
}

void stack_free(stack_t *stack)
{
    if (stack)
    {
        // 取消存活状态
        stack->status &= ~STACK_LIVE;
        if (stack->arr)
            free(stack->arr);
        free(stack);
    }
}

int stack_push(stack_t *stack, void *elem)
{
    if ((stack->status &= STACK_LIVE) == 0)
        return -1;

    if (stack->amout == stack->cap)
    {
        stack->cap *= 2;
        stack->arr = realloc(stack->arr, stack->cap * stack->elemsize);
        assert(stack->arr != NULL);
    }
    char *move_ptr = stack->arr;
    move_ptr += stack->elemsize * stack->amout;
    memcpy(move_ptr, elem, stack->elemsize);
    stack->amout++;
    return 0;
}

int stack_pop(stack_t *stack, void *result)
{
    if ((stack->status &= STACK_LIVE) == 0)
        return -1;

    if (stack->amout <= 0)
        return -2;

    stack->amout--;
    char *move_ptr = stack->arr;
    move_ptr += stack->elemsize * stack->amout;
    memcpy(result, move_ptr, stack->elemsize);
    return 0;
}
